package Noyau;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.xml.crypto.dsig.keyinfo.KeyValue;

import Outils.Dijkstra;
import Outils.DijkstraResult;
import Vue.ZComparator;

public class Aiguillage extends CheminChariot
{
	private InterfaceChariot sortieManuel = null;

	@Override
	public boolean PeutAjouterChariot(Chariot chariot)
	{
		// Check if there is already a Chariot
		if (this.chariots.size() > 0)
		{
			return false;
		}

		return true;
	}

	@Override
	public boolean AjouterChariot(Chariot chariot) {
		if (!this.PeutAjouterChariot(chariot))
		{
			return false;
		}

		this.CreerChariot(chariot);

		return true;
	}

	public boolean isWaitingForUser()
	{		
		if (this.chariots.size() == 0)
		{
			return false;
		}

		if (!this.getAeroport().isModeManuel())
		{
			return false;
		}
		
		if (this.sorties.size() == 1)
		{
			return false;
		}

		if (this.sortieManuel != null)
		{
			return false;
		}

		return true;
	}

	public boolean setSortieManuel(InterfaceChariot value)
	{
		if (!this.sorties.contains(value))
		{
			return false;
		}

		this.sortieManuel = value;

		this.setChanged();
		this.notifyObservers();

		return true;
	}

	@Override
	public void TickHorloge() 
	{
		/*
		 * Two cases here :
		 * 1 - We have two entree and one sortie, then we just give our chariot to the next element.
		 * 2 - We have one entree and two sortie, we need depending on the chariot status to route it through the right sortie.
		 */

		if (this.chariots.size() == 0 || this.sorties.size() == 0)
		{
			return;
		}

		Chariot chariot = this.chariots.get(0);

		// If the routing of this chariot is in manual mode, we stop here.
		if (this.getAeroport().isModeManuel())
		{
			if (this.sorties.size() == 1)
			{
				if (!this.sorties.get(0).AjouterChariot(chariot))
				{
					return;
				}
				
				this.chariots.remove(chariot);
				
				return;
			}
			
			if (this.sortieManuel == null)
			{
				return;
			}

			if (!this.sortieManuel.AjouterChariot(chariot))
			{
				return;
			}

			this.sortieManuel = null;
			this.chariots.remove(chariot);

			return;
		}

		if (this.sorties.size() == 1)
		{
			InterfaceChariot firstSortie = this.sorties.get(0);
			
			if (!firstSortie.AjouterChariot(chariot))
			{
				return;
			}

			this.chariots.remove(chariot);
		}
		else
		{
			DijkstraResult dijResult = Dijkstra.computeShortestPaths(this);			


			/*
			 * We have two possible cases here :
			 * 1 - The chariot is loaded with a bagage, we try to route it to the corresponding toboggant.
			 * 2 - The chariot is empty, we try to route it to the nearest empty Lien (with Sens == true)
			 */

			Chemin destination = null;

			if (chariot.getBagage() != null)
			{
				destination = chariot.getBagage().getArrivee();
			}
			else
			{
				// We first sort the elements in dist.
				List<CheminLien> liens = new ArrayList<CheminLien>();
				
				for (Chemin parcours : dijResult.getDist().keySet())
				{
					if (parcours instanceof CheminLien)
					{
						liens.add((CheminLien)parcours);
					}
				}
				
				Collections.sort(liens, new ValueComparator());

				// We find the nearest empty Lien.
				for (CheminLien lien : liens) {
					if (lien.isSens() && lien.getBagages().size() > 0)
					{
						destination = lien;
						break;
					}
				}

				// If we found no empty Lien, we now try to find the nearest Lien (empty or not).
				if (destination == null)
				{
					for (CheminLien lien : liens) {
						if (lien.isSens())
						{
							destination = lien;
							break;
						}
					}
				}
			}			

			// If the destination is still null, there is a problem with our graph.
			if (destination == null)
			{
				return;
			}

			// We find the next element corresponding to this destination, and try to give it the chariot.
			InterfaceChariot nextElement = (InterfaceChariot)Dijkstra.getNextElement(dijResult.getPrevious(), this, destination);

			if (!nextElement.AjouterChariot(chariot))
			{				
				return;
			}

			this.chariots.remove(chariot);
		}		

		this.setChanged();
		this.notifyObservers();
	}

	@Override
	public int getZBuffer()
	{
		return 10;
	}
}

class ValueComparator implements Comparator<CheminLien> 
{	
	@Override
	public int compare(CheminLien a, CheminLien b) {
		if ((a.getBagageCount() % 10) < (b.getBagageCount() % 10)) 
		{
			return -1;
		} 
		else if ((a.getBagageCount() % 10) == (b.getBagageCount() % 10))
		{
			return 0;
		} 
		else 
		{
			return 1;
		}
	}
}

